﻿#region Imports
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Media;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using ClipboardCapture.Properties;
using CommonUtilities.Attributes;
using CommonUtilities.Enums;
using CommonUtilities.Extensions;
using CommonUtilities.Info;
using CommonUtilities.Logging;
using CommonUtilities.Messages;
using CommonUtilities.Util;
using ResourceUtilities = CommonUtilities.Properties.Resources;
#endregion

namespace ClipboardCapture
{
    public partial class frmClipboardCapture : Form
    {
        #region Declarations
        [DefaultValue(eCaptureMode.Undeclared)]
        public enum eCaptureMode
        {
            /// <summary>
            /// Default selection when not implemented
            /// </summary>
            [Description("Default selection when not implemented")]
            [FriendlyName("Select a mode..")]
            Undeclared = 0,

            /// <summary>
            /// URLs
            /// </summary>
            [Description("URLs")]
            URLs,

            // RKD_1 [Description("{0}: {1}", )]
            /// <summary>
            /// Gets directory name from clipboard
            /// </summary>
            [Description("Gets directory name from clipboard")]
            [FriendlyName("Directory Names")]
            Directory_Name,

            /// <summary>
            /// Formats XML Metadata Comments from clipboard
            /// </summary>
            [Description("Formats XML Metadata Comments from clipboard")]
            [FriendlyName("Metadata Comments")]
            Metadata_Comments,

            /// <summary>
            /// Generates TV Series folder name with episode list from clipboard
            /// </summary>
            [FriendlyName("TV Series Folder Name")]
            [Description("Generates TV Series folder name with episode list from clipboard")]
            TV_Series_Folder_Name,

            /// <summary>
            /// Generates IMDB episode list from clipboard
            /// </summary>
            [FriendlyName("IMDB Episode List")]
            [Description("Generates IMDB episode list from clipboard")]
            IMDB_Episode_List,

            /// <summary>
            /// Trims MP3 suffix from clipboard
            /// </summary>
            [FriendlyName("MP3 Suffix Trimmer")]
            [Description("Trims MP3 suffix from clipboard")]
            MP3_Title_SongsPK_Trimmer,

            /// <summary>
            /// Copies data to clipboard
            /// </summary>
            [FriendlyName("Copy to Clipboard")]
            [Description("Copies data to clipboard")]
            Assign_Clipboard,

            /// <summary>
            /// Generates WPF Style Property Setters tags from clipboard
            /// </summary>
            [FriendlyName("WPF Style Property Setters")]
            [Description("Generates WPF Style Property Setters tags from clipboard")]
            WPF_Style_Setter,

            /// <summary>
            /// Sorts data from clipboard
            /// </summary>
            [FriendlyName("Data Sorter")]
            [Description("Sorts data from clipboard")]
            Data_Sorter,

            /// <summary>
            /// Converts IMDb URL to &apos;/title/tt0123456&apos;
            /// </summary>
            [FriendlyName("IMDB Series URL")]
            [Description("Converts IMDb URL to '/title/tt0123456'")]
            IMDB_Series_URL,

            /// <summary>
            /// Trims Amazon URL to &apos;.../dp/&lt;Amazon_ID&gt;&apos; format
            /// </summary>
            [FriendlyName("Amazon URL/Bookmark")]
            [Description("Trims Amazon URL to '.../dp/<Amazon_ID>' format")]
            AmazonBookmark,

            /// <summary>
            /// Formats Torrent trackers to insert a blank line as searator
            /// </summary>
            [FriendlyName("Torrent trackers")]
            [Description("Formats Torrent trackers")]
            TorrentTrackers,
        }

        bool isExitClicked = false;

        Dictionary<PictureBox, Color> colourMap = new Dictionary<PictureBox, Color>();

        public Point m_DragStart;
        public bool m_Dragging;
        #endregion Declarations

        #region Properties
        public ObservableCollection<string> allClipboardData = new ObservableCollection<string>();
        public ObservableCollection<string> AllClipboardData
        {
            get { return allClipboardData; }
            set { allClipboardData = value; }
        }

        public string LastValue { get; set; }

        public string ErrorValue { get; set; }

        private bool isCapturing;
        public bool IsCapturing
        {
            get { return isCapturing; }
            set
            {
                isCapturing = value;

                cmnuCapture.Enabled = btnCapture.Enabled = !isCapturing;
                cmnuStop.Enabled = btnStop.Enabled = isCapturing;
            }
        }

        private bool isMaximized;
        public bool IsMaximized
        {
            get { return isMaximized; }
            set { isMaximized = value; tltipMain.SetToolTip(picMaximize, isMaximized ? "Restore Down" : "Maximize"); }
        }

        List<string> AllMetadataHeaders = "Summary:Parameters:Returns:Exceptions:Type parameters:".Split(':')._Select(hdr => hdr + ":").ToList();
        List<string> AllMetadataParamlessHeaders = "Summary:Returns:".Split(':')._Select(hdr => hdr + ":").ToList();

        private bool hasError;
        private int tooltipTimeoutDuration = 2000;
        public bool HasError
        {
            get { return hasError; }
            set
            {
                hasError = value;

                if (hasError) lblError.ForeColor = Color.Red;
                else DisplayError();
            }
        }
        #endregion Properties

        #region Constructors
        /// <summary>
        /// Initializes a new deault instance of ClipboardCapture.frmClipboardCapture
        /// </summary>
        public frmClipboardCapture()
        {
            InitializeComponent();
            IsMaximized = (this.WindowState == FormWindowState.Maximized);

            ntfySysTray.Visible = true;
            NotifyInfo(Resources.Info_Initializing);

            UpdateTimerInterval();

            HasError = false;
            cmbMode.PopulateComboBoxWithEnum<eCaptureMode>(formatter: FormatCaptureMode);
            cmnuCapture.Enabled = btnCapture.Enabled = true;
            cmnuStop.Enabled = btnStop.Enabled = false;
        }
        #endregion Constructors

        #region Events
        private void frmClipboardCapture_Load(object sender, EventArgs e)
        {
            lblTitle.Text = this.Text;

            picIcon.BackColor = lblTitle.BackColor;

            picIcon.Image = Resources.ClipboardCapture.ToBitmap();
            picMinimize.Image = Resources.Window_Minimize;
            picMaximize.Image = Resources.Window_Maximize;
            picClose.Image = Resources.Window_Close;

            colourMap.AddToDictionary(picMinimize, Color.Yellow);
            colourMap.AddToDictionary(picMaximize, Color.Chartreuse);
            colourMap.AddToDictionary(picClose, Color.FromArgb(255, 128, 128));
        }

        private void frmClipboardCapture_TextChanged(object sender, EventArgs e)
        {
            lblTitle.Text = this.Text;
        }

        #region Clipboard capturing
        private void btnStart_Click(object sender, EventArgs e)
        {
            tmrActivator.Start();
            IsCapturing = true;
            MinimizeToTray();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            tmrActivator.Stop();
            IsCapturing = false;
        }

        private void tmrActivator_Tick(object sender, EventArgs e)
        {
            AddClipboardData();
        }

        private void ntfySysTray_DoubleClick(object sender, EventArgs e)
        {
            RestoreFromTray();
        }

        private void ntfySysTray_MouseMove(object sender, MouseEventArgs e)
        {
            // NotifyInfo();
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            Clipboard.Clear();
            AllClipboardData.Clear();
            txtClipboardData.Clear();
            NotifyInfo(Resources.Info_Cleared);
        }

        private void cmbMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            eCaptureMode selectedMode = (eCaptureMode)cmbMode.SelectedValue;

            // Wrapping
            bool isDenied = !(selectedMode == eCaptureMode.Assign_Clipboard);
            txtClipboardData.ReadOnly = isDenied;
            chkWrap.Visible = !isDenied;
            chkWrap_CheckedChanged(null, null);
            if (!isDenied) txtClipboardData.Focus();

            string info = selectedMode.GetEnumAttribute<eCaptureMode, DescriptionAttribute>().Description; // AttributeLists<eCaptureMode>.PropertyMapDescription[selectedMode.ToString()]  ; // cmbMode.Text
            if (!cmbMode.Text.IsNullOrEmpty()) tltipMain.SetToolTip(cmbMode, info);
        }

        private void numRefreshRate_ValueChanged(object sender, EventArgs e)
        {
            UpdateTimerInterval();
        }

        private void chkWrap_CheckedChanged(object sender, EventArgs e)
        {
            if (chkWrap.Visible) txtClipboardData.WordWrap = chkWrap.Checked;
            else txtClipboardData.WordWrap = false;
        }
        #endregion Clipboard capturing

        #region Window states
        private void picMinimize_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void picMaximize_Click(object sender, EventArgs e)
        {
            IsMaximized = !IsMaximized;
            this.WindowState = IsMaximized ? FormWindowState.Maximized : FormWindowState.Normal;
        }

        private void picClose_Click(object sender, EventArgs e)
        {
            try
            {
                isExitClicked = true;

                NotifyInfo(Resources.Info_Shutting);
                ToggleWindowState(true, true);

                Thread.Sleep(tooltipTimeoutDuration);
                Application.Exit();
            }
            catch (Exception) { }
        }

        private void frmClipboardCapture_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!isExitClicked) picClose_Click(sender, e);
        }
        #endregion Window states

        #region Move on drag
        private void lblTitle_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                m_DragStart = e.Location;
                m_Dragging = true;
            }
        }

        private void lblTitle_MouseMove(object sender, MouseEventArgs e)
        {
            if (m_Dragging && e.Button == MouseButtons.Left)
            {
                this.Location += new Size(e.Location.X - m_DragStart.X, e.Location.Y - m_DragStart.Y);
            }
        }

        private void lblTitle_MouseUp(object sender, MouseEventArgs e)
        {
            if (m_Dragging && e.Button == MouseButtons.Left) m_Dragging = false;
        }

        private void frmClipboardCapture_Resize(object sender, EventArgs e)
        {
            switch (this.WindowState)
            {
                case FormWindowState.Maximized:
                    picMaximize.Image = Resources.Window_Restore;
                    break;

                case FormWindowState.Normal:
                default:
                    this.StartPosition = FormStartPosition.CenterScreen;
                    picMaximize.Image = Resources.Window_Maximize;
                    break;
            }
        }
        #endregion Move on drag

        #region Animations
        private void picWindowState_MouseEnter(object sender, EventArgs e)
        {
            colourMap._Where(elem => elem.Key == (PictureBox)sender)._ForEach(elem => elem.Key.BackColor = elem.Value);
        }

        private void picWindowState_MouseLeave(object sender, EventArgs e)
        {
            colourMap._Where(elem => elem.Key == (PictureBox)sender)._ForEach(elem => elem.Key.BackColor = Color.Transparent);
        }
        #endregion Animations
        #endregion Events

        // RKD_1 COPY_ALL_TEXTS_TO_RESOURCE a;

        #region Methods
        private void AddClipboardData()
        {
            try
            {
                tmrActivator.Stop();

                string data = Clipboard.GetText().Trim();
                bool isModeUndefined = false;

                if (!data.IsBlank())
                {
                    // if (LastValue.IsBlank() || ErrorValue.IsBlank() || data != LastValue || data == ErrorValue)
                    if (data != LastValue || LastValue.IsBlank() || data == ErrorValue) // || ErrorValue.IsBlank()
                    {
                        switch ((eCaptureMode)cmbMode.SelectedValue)
                        {
                            case eCaptureMode.URLs:
                                #region eCaptureMode.URLs
                                if (data.ConvertStringToLines().RemoveEmptyLines().HasCount(1))
                                {
                                    //if (!Regex.IsMatch(data, @"/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/"))
                                    if (!Regex.IsMatch(data, @"[^(http|https|ftp)\://]([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&amp;%\$#\=~_\-]+))*$"))
                                    {
                                        NotifyError("No URL copied to clipboard..");
                                        if (LastValue != data) NotifyInfo("Invalid URL:{0}\"{1}\"".FormatTextFromParams(Utilities.cNewLine, data));
                                        LastValue = data;

                                        return;
                                    }

                                    if (!AllClipboardData.Contains(data))
                                    {
                                        AllClipboardData.Add(data);
                                        txtClipboardData.Lines = AllClipboardData.ToArray();

                                        NotifyInfo(data);

                                        LastValue = data;
                                        ErrorValue = null;
                                    }
                                }
                                else NotifyError(Resources.Err_MultiLineNotAllowed);
                                break;
                                #endregion eCaptureMode.URLs

                            case eCaptureMode.Directory_Name:
                                #region eCaptureMode.Directory_Name
                                //if (data.ConvertStringToLines().GetCount() > 1)
                                //    throw new InvalidOperationException("Only single-line text allowwd..");    

                                if (data.ValidatePath(ePathValidation.File))
                                    data = data.GetDirectoryNameFull();

                                if (data.ValidatePath(ePathValidation.Directory))
                                {
                                    char[] invalidChars = Resources.Const_InvalidPathCharacters.ToCharArray();
                                    data = "_" + data.GetDirectoryNameOnly().CapitalizeEachWord().RemoveText(invalidChars).Trim(invalidChars);
                                    if (!txtClipboardData.Text.ConvertStringToLines()._Contains(data))
                                        txtClipboardData.Text += data + Utilities.cNewLine;

                                    long cnt = txtClipboardData.Lines.RemoveEmptyLines().GetCount();
                                    this.Text = "({0}) {1}..".FormatTextFromParams(cnt, AppInfo.AssemblyTitle);

                                    Clipboard.SetText(data);
                                    NotifyInfo(data);

                                    LastValue = data;
                                    ErrorValue = null;
                                }
                                break;
                                #endregion eCaptureMode.Directory_Name

                            case eCaptureMode.Metadata_Comments:
                                #region eCaptureMode.Metadata_Comments
                                try
                                {
                                    if (!data.IsNullOrEmpty() & data != LastValue
                                        & Form.ModifierKeys._HasFlags<Keys>(eAndOrNone.All, Keys.Control, Keys.Shift, Keys.Alt))
                                    {
                                        data += Utilities.cNewLine;
                                        data = data.FormatXmlTags().ConvertStringToLines()._Select(val =>
                                        {
                                            val = val.Trim().TrimStart('/').Trim();
                                            val = (val.IsNullOrEmpty() ? ResourceUtilities.Logger_Separator : val);

                                            return val;
                                        }).ConvertLinesToString();

                                        Dictionary<string, Dictionary<string, string>> dictData = new Dictionary<string, Dictionary<string, string>>();
                                        string currHeader = ""; string dataMultiline = ""; string param = "";

                                        foreach (string val in data.ConvertStringToLines())
                                        {
                                            if (AllMetadataHeaders._Contains(val)) // Header
                                            {
                                                currHeader = val; dataMultiline = "";
                                                dictData.AddToDictionary(currHeader, new Dictionary<string, string>());
                                            }
                                            else if (!currHeader.IsNullOrEmpty() && val != ResourceUtilities.Logger_Separator) // Params (no breaks encountered)
                                            {
                                                if (param.IsNullOrEmpty()) param = (AllMetadataParamlessHeaders._Contains(currHeader) ? currHeader : val); // Add parameter (use header if param is absent)

                                                if (dataMultiline.IsNullOrEmpty() & (AllMetadataParamlessHeaders._Contains(val) || param == val)) continue; // Skip adding comments if new and belongs to 'Direct Headers'

                                                dataMultiline += val + " "; // Add comments
                                            }
                                            else if (!currHeader.IsNullOrEmpty() && val == ResourceUtilities.Logger_Separator) // .IsNullOrEmpty()) // Comments (break encountered)
                                            {
                                                IEnumerable<string> words = dataMultiline.ToWords();

                                                dictData[currHeader].AddToDictionary(param, dataMultiline.Trim());
                                                param = dataMultiline = "";
                                            }
                                        }

                                        data = FormatMetadataComments(dictData);

                                        Clipboard.SetText(data);
                                        NotifyInfo(data);

                                        LastValue = data;
                                        ErrorValue = null;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    NotifyError(ex.Message);
                                    // MessageBoxUtil.Show(Debugger.IsAttached, "An error occurred: " + ex.ToString());
                                }
                                break;
                                #endregion eCaptureMode.Metadata_Comments

                            case eCaptureMode.MP3_Title_SongsPK_Trimmer:
                                #region eCaptureMode.MP3_Title_SongsPK_Trimmer
                                try
                                {
                                    int len = data.ToLower().IndexOf("- www.Songs.PK".ToLower());
                                    Clipboard.SetText(data.TrimAndTake(len, eTrimDirection.Left).Trim());
                                    NotifyInfo(data);
                                    SystemSounds.Asterisk.Play();
                                }
                                catch (Exception ex) { NotifyError(ex.Message); }

                                LastValue = data;
                                ErrorValue = null;
                                break;
                                #endregion eCaptureMode.MP3_Title_SongsPK_Trimmer

                            case eCaptureMode.Assign_Clipboard:
                                #region eCaptureMode.Assign_Clipboard
                                if (!txtClipboardData.Text.IsNullOrEmpty())
                                { if (data != txtClipboardData.Text) { Clipboard.SetText(txtClipboardData.Text); NotifyInfo(Resources.Info_CopiedToClipboard); } }
                                else NotifyError(Resources.Err_NoValueForClipboard);
                                SystemSounds.Asterisk.Play();
                                break;
                                #endregion eCaptureMode.Assign_Clipboard

                            case eCaptureMode.WPF_Style_Setter:
                                #region eCaptureMode.WPF_Style_Setter
                                if (data.IsBlank() || data.Contains("<Setter")) break;

                                string template = "<Setter Property=\"{0}\" Value=\"{1}\" />" + Utilities.cNewLine;
                                IEnumerable<string> properties = data.ConvertStringToLines()._Select(ln => ln.ToWords()).SelectMany(wrd => wrd);

                                data = "";
                                properties.RemoveEmptyWords()._ForEach(wrd =>
                                {
                                    string[] pair = wrd.Split('=');
                                    data += template.FormatTextFromParams(pair.First(), pair.Last().RemoveText("\""));
                                });

                                Clipboard.SetText(data);
                                NotifyInfo(data);

                                LastValue = data;
                                ErrorValue = null;
                                break;
                                #endregion eCaptureMode.WPF_Style_Setter

                            case eCaptureMode.Data_Sorter:
                                #region eCaptureMode.Data_Sorter
                                data = data.ConvertStringToLines()._Select(val => val.Trim())._OrderBy(val => val).ConvertLinesToString();

                                Clipboard.SetText(data);
                                NotifyInfo(data);

                                LastValue = data;
                                ErrorValue = null;
                                break;
                                #endregion eCaptureMode.Data_Sorter

                            case eCaptureMode.IMDB_Series_URL:
                                #region eCaptureMode.IMDB_Series_URL
                                if (data.Contains("www.imdb.com") && !data.Contains("/find?q="))
                                {
                                    var arr = data.Split('/');
                                    int i = arr.ToList().IndexOf("www.imdb.com");
                                    arr = arr.Skip(i + 1).ToArray();
                                    arr = arr.Take(2).ToArray();
                                    arr = arr.AddItem(".").ToArray();
                                    data = "".AppendText("/", arr).Trim('.');

                                    Clipboard.SetText(data);
                                    NotifyInfo(data);

                                    LastValue = data;
                                    ErrorValue = null;
                                }
                                break;
                                #endregion eCaptureMode.IMDB_Series_URL

                            case eCaptureMode.AmazonBookmark:
                                #region eCaptureMode.AmazonBookmark
                                if (data.Contains("amazon"))
                                {
                                    // https://www.amazon.co.uk/Polaroid-P-600-Instant-Camera/dp/B00AS977R2/ref=sr_1_6?s=photo&ie=UTF8&qid=1463818566&sr=1-6&keywords=polaroid
                                    // http://www.amazon.in/Philips-SHE1360-97-Headphone-Black/dp/B005YH826S?ie=UTF8&redirect=true&ref_=br_asw_pdt-3

                                    var linkParts = data.Split("/?".ToCharArray()).ToList();

                                    string result = String.Empty;
                                    linkParts.Take(linkParts.IndexOf("dp") + 2).ForEach(lnk => result += lnk + "/");

                                    Clipboard.SetText(result);
                                    NotifyInfo(String.Format("{0}\r\nDomain: {1}\r\nID: {2}\r\nName: {3}", data, linkParts[2], linkParts[5], linkParts[3]));

                                    LastValue = data;
                                    ErrorValue = null;
                                }
                                break;
                                #endregion eCaptureMode.AmazonBookmark

                            case eCaptureMode.TorrentTrackers:
                                #region eCaptureMode.TorrentTrackers
                                if (!data.IsBlank())
                                {
                                    string result = String.Empty;
                                    data.ConvertStringToLines().RemoveEmptyLines().ForEach(ln => result += ln + Environment.NewLine.Repeator(2));
                                    result = result.Trim();

                                    Clipboard.SetText(result);
                                    NotifyInfo(result);

                                    LastValue = result;
                                    ErrorValue = null;
                                }
                                break;
                                #endregion eCaptureMode.TorrentTrackers


                            default:
                                isModeUndefined = true;
                                bool cond = ErrorValue.IsNullOrEmpty() || LastValue != data;
                                ErrorValue = LastValue = data;
                                if (cond) throw new InvalidOperationException("Specify functionality for new enum..");
                                break;
                        }
                    }
                }

                if (!isModeUndefined) HasError = false; // & data != LastValue
                isModeUndefined = false;
            }
            catch (Exception ex)
            {
                HasError = true;
                string errMsg = ex.Message + Utilities.cNewLine.Repeator(2) + ex.StackTrace;

                NotifyError(ex.Message);
                Logger.WriteToLog(Program.Logger, errMsg, null, null, ex, EventLogEntryType.Error);
            }
            finally { tmrActivator.Start(); }
        }

        private string FormatMetadataComments(Dictionary<string, Dictionary<string, string>> dictData)
        {
            string result = "";
            foreach (string header in dictData.Keys)
            {
                if ("Summary:Returns".Split(':')._Contains(header.Trim(':')))
                    result += "<" + header.ToLower().Trim(':') + ">" + Utilities.cNewLine;

                foreach (string param in dictData[header].Keys)
                {
                    string comment = dictData[header][param].ToWords()
                        ._Select(wrd => wrd.Trim('.').ToCharStringArray().CountIf(".") > 1
                            ? "<code>" + wrd + "</code>" : wrd).ToSentence().Trim();

                    if (param == header)
                        result += comment + Utilities.cNewLine;
                    else
                    {
                        switch (header.Trim(':'))
                        {
                            case "Parameters":
                                result += "<param name=\"{0}\">".FormatTextFromParams(param.Trim(':'));
                                result += comment;
                                result += "</param>" + Utilities.cNewLine;
                                break;

                            case "Exceptions":
                                result += "<exception cref=\"{0}\">".FormatTextFromParams(param.Trim(':'));
                                result += comment;
                                result += "</exception>" + Utilities.cNewLine;
                                break;

                            case "Type parameters":
                                result += "<typeparam name=\"{0}\">".FormatTextFromParams(param.Trim(':'));
                                result += comment;
                                result += "</typeparam>" + Utilities.cNewLine;
                                break;

                            default:
                                break;
                        }
                    }
                }

                if ("Summary:Returns".Split(':')._Contains(header.Trim(':')))
                    result += "</" + header.ToLower().Trim(':') + ">" + Utilities.cNewLine;
            }

            result = result.Trim().TrimEnd('/'); // .TrimEnd(Utilities.cNewLine.ToCharArray());
            return result.ConvertStringToLines()._Select(ln => "/// " + ln).ConvertLinesToString();
        }

        private object FormatCaptureMode(object src)
        {
            return ((eCaptureMode)src).GetEnumAttributeProperty<eCaptureMode, string>("FriendlyNameAttribute", "FriendlyName", src.ToString()).Replace("_", " ");
        }

        private void MinimizeToTray()
        {
            ToggleWindowState(true, false);
        }

        private void RestoreFromTray()
        {
            ToggleWindowState(false, false);
        }

        public void ToggleWindowState(bool isMinToTray, bool suppressInfo)
        {
            this.ShowInTaskbar = this.Visible = !isMinToTray;
            if (suppressInfo) return;

            NotifyInfo();
            NotifyInfo(GetState(IsCapturing));
        }

        private string GetState(bool isMinToTray)
        {
            return Resources.Msg_WindowState.FormatTextFromParams(isMinToTray ? Resources.Msg_StateCapturing : Resources.Msg_StateStopped);
        }

        private void NotifyInfo(string message = "")
        {
            SystemSounds.Asterisk.Play();
            DisplayError();

            if (message.IsNullOrEmpty()) message = Resources.Msg_AppRunningBG.FormatTextFromParams(AppInfo.AssemblyTitle);
            ShowBalloonTip(message, ToolTipIcon.Info);
        }

        private void NotifyError(string message)
        {
            SystemSounds.Hand.Play();
            DisplayError(message);

            ShowBalloonTip(message, ToolTipIcon.Error);
        }

        private void ShowBalloonTip(string message, ToolTipIcon notificationMode)
        {
            string mode = Convert.ToString(FormatCaptureMode(cmbMode.SelectedValue.Coalesce(eCaptureMode.Undeclared)));
            string tooltipMessage = Resources.Tooltip_Message;

            if (message == Resources.Info_Initializing || message == Resources.Info_Shutting || message == Resources.Info_Cleared)
            { mode = message; tooltipMessage = "{0}"; }

            ntfySysTray.ShowBalloonTip(tooltipTimeoutDuration,
                Resources.Tooltip_Title.FormatTextFromParams(AppInfo.AssemblyTitle, notificationMode.ToString()),
                tooltipMessage.FormatTextFromParams(mode, message), notificationMode);
        }

        private void DisplayError(string message = "")
        {
            if (message.IsNullOrEmpty())
            {
                lblError.Text = "No errors..";
                lblError.ForeColor = Color.Green;
            }
            else
            {
                lblError.Text = message;
                lblError.ForeColor = Color.Red;
            }
        }

        private void UpdateTimerInterval()
        {
            try
            {
                tmrActivator.Interval = (1000 / numRefreshRate.Value).ChangeType<int>();
                tltipMain.SetToolTip(numRefreshRate,
                    "Refresh rate in Hz\n[ rate = {0} ]".FormatTextFromParams(numRefreshRate.Value == 1 ? "1s" : "1/{0}s = {1}ms").FormatTextFromParams(numRefreshRate.Value, (1000 / numRefreshRate.Value).ChangeType<int>()));
            }
            catch (Exception ex) { MessageBoxUtil.Show(true, "Value : {0}\nError: {1}".FormatTextFromParams(numRefreshRate.Value, ex.Message)); }
        }
        #endregion Methods
    }
}
